package main

import (
	"fmt"
	"time"
)

// go DAG 2023/08/17 01:09
// todo 写简化版本规则引擎 参考byteFlow

// 节点
type Node struct {
	Id   string
	Data string
}

// 边 暂时只要节点依赖关系就行
/*type Edge struct {
	From   Node `json:"from"`
	To     Node `json:"to"`
	TwoWay bool `json:"two-way"`
}*/

type Forest struct {
	readyNodes map[string]Node
	allNodes   map[string]Node
	inDegree   map[string]int
	nextSlice  map[string]map[string]struct{}
}

func (n *Node) run() {
	fmt.Println("node ", n.Id, " executed, data is ", n.Data)
}

// 森林添加节点
func (f *Forest) addNode(nodes ...Node) {
	for _, node := range nodes {
		if _, ok := f.allNodes[node.Id]; !ok {
			f.readyNodes[node.Id] = node
			f.allNodes[node.Id] = node
		} else {
			fmt.Println("node ", node.Id, "existed")
		}
	}
}

// 森林添加节点
func (f *Forest) addEdge(fromId, toId string) {
	_, okFrom := f.allNodes[fromId]
	_, okTo := f.allNodes[toId]
	if okFrom && okTo {
		var nexts map[string]struct{}
		var ok bool
		if nexts, ok = f.nextSlice[fromId]; !ok {
			f.nextSlice[fromId] = make(map[string]struct{})
			nexts = f.nextSlice[fromId]
		}
		nexts[toId] = struct{}{}
		// 入度不为0从顶部节点移除
		delete(f.readyNodes, toId)
		f.inDegree[toId]++
	} else {
		// 节点不存在报错
		fmt.Errorf("node %s %s not existed", fromId, toId)
	}
}

// 主go程 将可以异步的node提交给子goroutine
func (f *Forest) run() {

	readyNodes := make(chan Node, 32)
	quit := make(chan int)
	go f.executeNodes(readyNodes, quit)
	for _, node := range f.readyNodes {
		readyNodes <- node
	}
	select {
	case <-quit:
		return
	case <-time.After(time.Millisecond * 100):
		fmt.Println("已经超时")
		return
	}
}

// 子go程 异步自调用 发现可以运行的node提交到channel中并自己运行
// 发现无node可提交时结束  发送消息给quit channel中
func (f *Forest) executeNodes(readyNodes chan Node, quit chan int) {
	defer func() {
		close(readyNodes)
		quit <- 1
	}()

	// 终止条件 ：邻接表空了  没必要继续跑了 这里可以支持多协程提交了
	// 如何进行多协程提交？map线程安全问题需要处理
	for len(f.nextSlice) > 0 {
		node := <-readyNodes
		node.run()
		if nexts, ok := f.nextSlice[node.Id]; ok {
			for k, _ := range nexts {
				f.inDegree[k]--
				if f.inDegree[k] == 0 {
					readyNodes <- f.allNodes[k]
				}
			}

			delete(f.nextSlice, node.Id)
		}
	}
	for len(readyNodes) > 0 {
		node := <-readyNodes
		node.run()
	}
}

func main() {
	forest := Forest{}
	forest.inDegree = make(map[string]int)
	forest.allNodes = make(map[string]Node)
	forest.readyNodes = make(map[string]Node)
	forest.nextSlice = make(map[string]map[string]struct{})
	n1 := Node{"1", "node1"}
	n2 := Node{"2", "node2"}
	n3 := Node{"3", "node3"}
	// 3必定最后一个运行
	forest.addNode(n1, n2, n3)
	forest.addEdge("1", "3")
	forest.addEdge("2", "3")
	forest.run()
}
